import java.util.ArrayList;
import java.util.List;


public enum InstanceType {

    // Standard instances
   	M1SMALL(1740, 1, 1, 160, 1000, Bits.B32, "m1.small", 1) {
   		@Override
    	public long getOnDemandPrice() {
			return 60; //0.085$
		}
   		@Override
		public long getReservedPrice() {
			return 21; //0.05$
		}
    },
    M1LARGE(7680, 4, 2, 850, 1000, Bits.B64, "m1.large", 1) {
    	@Override
    	public long getOnDemandPrice() {
			return 340; //0.34$
		}
    	@Override
		public long getReservedPrice() {
			return 120;
		}
    },
    M1XLARGE(15360, 8, 4, 1690, 1000, Bits.B64, "m1.xlarge", 1) {
    	@Override
    	public long getOnDemandPrice() {
			return 680; //0.68$
		}
    	@Override
		public long getReservedPrice() {
			return 240; //0.24$
		}
    },

    // High-memory instances
    M2XLARGE(17510, 6.5, 2, 420, 1000, Bits.B64, "m2.xlarge", 1) {
    	@Override
    	public long getOnDemandPrice() {
			return 500;
		}
    
	@Override
		public long getReservedPrice() {
			return 170;
		}
    },
    M22XLARGE(35020, 13, 4, 850, 1000, Bits.B64, "m2.2xlarge", 1) {
    	@Override
    	public long getOnDemandPrice() {
			return 1000;
		}
    	@Override
		public long getReservedPrice() {
			return 340;
		}
    },
    M24XLARGE(70041, 26, 8, 1690, 1000, Bits.B64, "m2.4xlarge", 1) {
    	@Override
   		public long getOnDemandPrice() {
    		return 20;
    	}
    	@Override
    	public long getReservedPrice() {
    	
	return 68;
    	}
    },

    // High-CPU instances
    C1MEDIUM(1740, 5, 2, 320, 1000, Bits.B32, "c1.medium", 1) {
    	@Override
		public long getOnDemandPrice() {
	    	return 17;
		}
		@Override
		public long getReservedPrice() {
		
	return 6;
		}
    },
    C1XLARGE(7189, 20, 8, 1690, 1000, Bits.B64, "c1.xlarge", 1) {
    	@Override
		public long getOnDemandPrice() {
			return 68;
		}
		@Override
		public long getReservedPrice() {
			return 24;
		}
    };

    public static final InstanceType maxCPUUnitsInstance = M24XLARGE;
    public static final InstanceType maxCoresUnitsInstance = M24XLARGE;
    public static final InstanceType maxMemoryInstance = M24XLARGE;

    public enum Bits {
	B32,
	B64;
    }

    
    public enum InstanceStatus {

        PENDING,
        RUNNING_IDLE,
        RUNNING_BUSY,
        SUSPENDED,
        MARKED_FOR_TERMINATION,
        TERMINATED_BY_USER,
        OUT_OF_BID,
        FAILED,
        BOOTING;

        public boolean isUsable() {
    	return equals(RUNNING_BUSY) || isIdle();
        }

        public boolean isIdle() {
    	return equals(RUNNING_IDLE) || equals(MARKED_FOR_TERMINATION);
        }
    }
    
    public enum PriceModel {
	RESERVED,
	ON_DEMAND,

	SPOT;
	
	public static PriceModel getModelFromName(String name) {
		for (PriceModel model: PriceModel.values()) {
			if (model.toString().equalsIgnoreCase(name)) {
				return model;
			}
		}
		return null;
	}
	
	public static int getInt(PriceModel model) {
		switch(model){
		case RESERVED: return 0;
		case ON_DEMAND:return 1;
		case SPOT:return 2;
		}
		return -1;
	}
	
    }

    public enum OS {
	LINUX {
	    @Override
	    public String getAmazonName() {
		return "Linux/UNIX";
	    }

	    @Override
	    public String getNameForFile() {
		return "linux";
	    }
	},
	WINDOWS {
	    @Override
	    public String getAmazonName() {
		return "Windows";
	    }

	    @Override
	    public String getNameForFile() {
		return "windows";
	    }
	};

	public abstract String getAmazonName();

	public abstract String getNameForFile();

    }

    /** Memory in MB */
    private final int mem;

    /**
     * Total number of EC2 compute units (equivalent to Number of cores * EC2
     * compute units per core
     */
    private final double ec2units;

    /** Number of CPU cores */
    private final int cores;

    /** Local disk storage in GB */
    private final long storage;

    /** 32 or 64 bits */
    private final Bits bits;

    /** Network bandwidth */
    private final long bw;

    private final String name;

    private double computePowerPerUnit;

    InstanceType(int mem, double ec2units, int cores, long storage, long bw, Bits bits,
	    String name, double gFlopsPerUnit) {
	this.mem = mem;
	this.ec2units = ec2units;
	this.cores = cores;
	this.storage = storage;
	this.bw = bw;
	this.bits = bits;
	this.name = name;
	this.computePowerPerUnit = gFlopsPerUnit;
    }

    public abstract long getOnDemandPrice();
    public abstract long getReservedPrice();

    public static List<String> getAllTypeNames() {
	List<String> allTypes = new ArrayList<String>();
	for (InstanceType type : InstanceType.values()) {
	    allTypes.add(type.getName());

	}
	return allTypes;
    }

    public String getName() {
	return this.name;
    }

    public int getMem() {
	return this.mem;
    }

    public double getEc2units() {
	return this.ec2units;
    }

    public int getCores() {
	return this.cores;
    }

    public long getStorage() {
	return this.storage;
    }

    public Bits getBits() {
	return this.bits;
    }

    public double getComputePowerPerCore() {
	return getComputePower() / getCores();
    }

    public double getComputePower() {
	return getEc2units() * getComputePowerPerUnit();
    }

    public long getBandwidth() {
	return this.bw;
    }

    @Override
    public String toString() {
	return getName();
    }

    public double getComputePowerPerUnit() {
	return this.computePowerPerUnit;
    }

}
 